#ifndef _Philosophers_Person_h_
#define _Philosophers_Person_h_

#include <CtrlLib/CtrlLib.h>

using namespace Upp;

// Possible states
enum PersonState { Thinking, Eating, Waiting };

// Displayed info
struct PersonInfo {
	volatile bool lfork, rfork;
	int hunger;
	int fork;
	PersonState state;
};

// Possible FTAs (fork taking algorithms):
enum FTA {	Simple, // without deadlock protection, left first
			Random, // without deadlock protection, first random
			Ordered, // with deadlock protection, ordered
			Voluntary // with deadlock protection, voluntary
};


// Philosopher person class
class Person {
	typedef Person CLASSNAME;
	
	// Game parameters:
	int id; // identifier
	String name; // name
	int productv; // productivity level
	int appetite; // appetite level
	int *speed; // game speed pointer
	FTA algo; // fork taking algo
	
	// Auxilliary fields and object state:
	PersonInfo info; // currently displayed info
	Thread thrd; // execution thread
	volatile bool running; // main cycle running flag
	int thinkTime, eatTime, waitTime; // basic waiting period
	#ifdef PLATFORM_POSIX // fix for U++ 2007.1
	volatile bool ret; // voluntary thread termination flag
	#endif
	
	// Interoperation fields:
	static long long grc; // global readyness counter
	static CriticalSection gcs; // global counter critical section
	static const long long maxReady = 9223372036854775807LL; // max value for ready
	Person *left, *right; // neighbor pointers
	CriticalSection cs; // critical section (mutex), contained in this container object
	int fork; // a fork, contained in this container object
	volatile bool free; // a flag, contained in this container object
	long long ready; // this philosopher readyness counter
	
	// Auxilliary functions:
	void CalcTime(); // delay calculation
	void Think(); // think
	void Eat(); // eat
	void Wait(); // wait
	void TakeForks(); // take forks
	void TakeSimple(); // simple algo
	void TakeRandom(); // random algo
	void TakeOrdered(); // ordered algo
	void TakeVoluntary(); // effective algo
	void PutForks(); // put forks
	void SendForks(); // give forks (voluntary)
	void Work(); // main cycle
	
public:
		// Const params
	static const int minProductivity = 1; // min. productivity
	static const int maxProductivity = 10; // max. productivity
	static const int minAppetite = 1; // min. appetite
	static const int maxAppetite = 10; // max. appetite
	static const int rndFactor = 3; // randomness factor
	
	// User interface callbacks:
	Callback1<String> Log; // logging callback
	Callback2<int, PersonInfo> Update; // state update callback
	Callback2<int, int> UpdateFork; // contained fork update callback
	
	// ctor/dtor
	Person(const String, int, int, FTA, int *); // ctor
	Person(const Person &); // copy ctor
	~Person(); // dtor
	
	// Control methods:
	void Run(); // executes main cycle
	void Stop(); // stops after current cycle
	void Terminate(); // forced termination
	void LinkRight(Person &); // links to right neighbor (after the list of philosophers has been formed)
	void LinkLeft(Person &); // links to left neighbor
	
	// Overloaded operators:
	void operator=(const Person &); // copy assignment
	inline void operator<<(Person & p) { LinkRight(p); }
	inline void operator>>(Person & p) { LinkLeft(p); }
	
	// Properties:
	// id
	inline int GetId() const { return id; }
	inline void SetId(int _id) { if(_id >= 0) id = _id; }
	// name
	inline String GetName() const { return name; }
	inline void SetName(const String _name) { name = _name; }
	// algo
	inline FTA GetAlgo() const { return algo; }
	inline void SetAlgo(FTA _algo) { algo = _algo; }
	// productivity
	inline int GetProductivity() const { return productv; }
	inline void SetProductivity(int _prod) { if(_prod >= minProductivity && _prod <= maxProductivity) productv = _prod; }
	// appetite
	inline int GetAppetite() const { return appetite; }
	inline void SetAppetite(int _appet) { if(_appet >= minAppetite && _appet <= maxAppetite) appetite = _appet; }
	// state info
	PersonInfo GetInfo();
	// running flag
	inline bool IsRunning() const { return running; }
};

#endif
